#pragma once

#include "Thread.hpp"
#include "Log.hpp"
#include "LockGuard.hpp"
#include <iostream>

#include <vector>
#include <queue>
#include <pthread.h>

using namespace ThreadModule;

const static int DefaultThreadNum = 5;

template <typename T>
class ThreadPool
{
private:
  void LockQueue()
  {
    pthread_mutex_lock(&_mutex);
  }
  void UnlockQueue()
  {
    pthread_mutex_unlock(&_mutex);
  }
  void ThreadSleep()
  {
    pthread_cond_wait(&_cond, &_mutex);
  }
  void ThreadWake()
  {
    pthread_cond_signal(&_cond);
  }
  void ThreadWakeAll()
  {
    pthread_cond_broadcast(&_cond);
  }
  ThreadPool(int threadnum = DefaultThreadNum) : _threadnum(threadnum), _waitnum(0), _isrunning(false)
  {
    pthread_mutex_init(&_mutex, nullptr);
    pthread_cond_init(&_cond, nullptr);
    LOG(INFO, "ThreadPool Construct()");
  }
  void initThreadPool()
  {
    for (int num = 0; num < _threadnum; num++)
    {
      std::string name = "thread -" + std::to_string(num + 1);
      // _threads.emplace_back(Print, name)
      _threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1), name); // 绑定
      LOG(INFO, "Init Thread %s done", name.c_str());
    }
    _isrunning = true;
  }
  void Start()
  {
    for (auto &thread : _threads)
    {
      thread.Start();
    }
  }
  // 类的成员方法也可以成为另一个类（Thread）的回调方法
  void HandlerTask(std::string name) // 包含this指针
  {
    LOG(INFO, "Thread %s is running...", name.c_str());
    while (true)
    {
      // 1.保证队列安全
      LockQueue();
      // 2.队列中不一定有数据
      while (_task_queue.empty() && _isrunning)
      {
        _waitnum++;
        ThreadSleep();
        _waitnum--;
      }
      // 2.1如果任务队列为空并且线程池已经退出
      if (_task_queue.empty() && !_isrunning)
      {
        UnlockQueue();
        break;
      }
      // 2.2如果任务队列非空并且线程池未退出
      // 2.3如果任务队列非空并且线程池已退出 --处理完任务再退出
      // 3.到这一定有任务，处理任务
      T t = _task_queue.front();
      _task_queue.pop();
      UnlockQueue();
      LOG(DEBUG, "%s get a task", name.c_str());
      // 4.处理任务，这个任务属于线程私有（独占）任务，所以不放到加锁解锁之间
      t();
      // LOG(DEBUG, "%s handler a task,result is %s", name.c_str(), t.ResultToString().c_str());
    }
  }
  // 禁止赋值拷贝
  ThreadPool(const ThreadPool<T> &) = delete;
  ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

public:
  static ThreadPool<T> *GetInstance()
  {
    // 只有第一次会创建对象，后续都是获取
    // 双判断的方式，可以有效减少获取单例的加锁成本，而且保证线程安全
    if (_instance == nullptr)
    {
      LockGuard lockguard(&_lock);
      if (_instance == nullptr)
      {
        _instance = new ThreadPool<T>();
        _instance->initThreadPool();
        _instance->Start();
        LOG(DEBUG, "创建线程池实例");
        return _instance;
      }
    }
    LOG(DEBUG, "获取线程池实例");
    return _instance;
  }
  void Stop()
  {
    LockQueue();
    _isrunning = false;
    ThreadWakeAll();
    UnlockQueue();
  }
  void Wait()
  {
    for (auto &thread : _threads)
    {
      thread.Join();
      LOG(INFO, "Thread %s is quit...", thread.name().c_str());
    }
  }
  bool Enqueue(const T &t)
  {
    bool ret = false;
    LockQueue();
    if (_isrunning)
    {
      _task_queue.push(t);
      if (_waitnum > 0)
      {
        ThreadWake();
      }
      LOG(DEBUG, "enqueue task success");
      ret = true;
    }
    UnlockQueue();
    return ret;
  }
  ~ThreadPool()
  {
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
  }

private:
  int _threadnum;
  std::vector<Thread> _threads; // 管理线程
  std::queue<T> _task_queue;    // 任务队列
  pthread_mutex_t _mutex;
  pthread_cond_t _cond;

  int _waitnum;
  bool _isrunning;

  // 添加单例模式
  static ThreadPool<T> *_instance;
  static pthread_mutex_t _lock;
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;